---
title: Using the Terraform Docker Provider
---

<div class="container" style="padding-top: 0px;">
  <div class="row">
    <div class="col-12">
      <div class="jumbotron">
        <h1 class="display-3">
          Terraform Docker Provider
        </h1>
        <p class="lead">
          This is an example of how to utilize Kitchen-Terraform to test a Docker container running on localhost configured with the <a href="https://www.terraform.io/docs/providers/docker/index.html" style="color: #32c850;">Terraform Docker Provider</a>.
        </p>
        <div class="float-right">Author: Erik R. Rygg</div>
        <br>
        <div class="float-right">Updated by: Carlos Gutierrez</div>
      </div>
    </div>
  </div>
  <div class="row">
    <div class="col-4">
      <div class="list-group" id="list-tab" role="tablist">
        <a class="list-group-item list-group-item-action active" id="list-one-list" data-toggle="list" href="#list-one" role="tab" aria-controls="one">
          1. Requirements & Setup
        </a>
        <a class="list-group-item list-group-item-action" id="list-two-list" data-toggle="list" href="#list-two" role="tab" aria-controls="two">
          2. Create Terraform code
        </a>
        <a class="list-group-item list-group-item-action" id="list-three-list" data-toggle="list" href="#list-three" role="tab" aria-controls="three">
          3. Create Terraform outputs
        </a>
        <a class="list-group-item list-group-item-action" id="list-four-list" data-toggle="list" href="#list-four" role="tab" aria-controls="four">
          4. Create tests
        </a>
        <a class="list-group-item list-group-item-action" id="list-five-list" data-toggle="list" href="#list-five" role="tab" aria-controls="five">
          5. Run tests
        </a>
      </div>
    </div>
    <div class="col-8">
      <div class="tab-content" id="nav-tabContent">
        <div class="tab-pane fade show active" id="list-one" role="tabpanel" aria-labelledby="list-one-list">
          Requirements are a Docker host listening on the Unix socket located at: unix:///var/run/docker.sock.
          <br><br>
          The Docker container that will be tested must be running an SSH daemon in the foreground to enable the
          Kitchen-Terraform verifier to remotely execute tests.
          <br><hr>
          To setup the project, run the following commands in the terminal:
          <br><br>
          <% code("bash") do %>
mkdir -p docker_provider_example/test/integration/example/controls
cd docker_provider_example
          <% end %>
          Create the <p class="font-weight-bold" style="color: #32c850; display: inline;">Gemfile</p> in the root of the project by running:
          <br><br>
          <% code("bash") do %>touch Gemfile<% end %>
          In this file we will place the dependencies that are required for the project by copying the code below into
          the <p class="font-weight-bold" style="color: #32c850; display: inline;">Gemfile</p>.
          <br><br>
          <% code("ruby") do %>
source 'https://rubygems.org/' do
  gem 'kitchen-terraform', '~> 7.0'
end
          <% end %>
          Next we to install kitchen-terraform and the other rubygems required, we also need to install bundler if it is
          not installed yet, by running the commands below in a terminal in the root of the project:
          <br><br>
          <% code("bash") do %>
gem install bundler
bundle install
          <% end %>
          Create a <p class="font-weight-bold" style="color: #32c850; display: inline;">.kitchen.yml</p> file in the root of the project.
          <br><br>
          <% code("bash") do %>
touch .kitchen.yml
          <% end %>
          This file brings together the Terraform module code and Inspec controls. Copy the configuration below into the
          <p class="font-weight-bold" style="color: #32c850; display: inline;">.kitchen.yml</p> file.
          <br><br>
          <div class="row">
            <div class="col">
              <% code("yml") do %>
---
driver:
  name: terraform

provisioner:
  name: terraform

verifier:
  name: terraform
  systems:
    - name: docker container
      backend: ssh
      password: root
      hosts_output: container_host
      controls:
        - operating_system
      port: 2222
    - name: localhost
      backend: local
      controls:
        - state_files

platforms:
  - name: ubuntu

suites:
  - name: example

              <% end %>
            </div>
            <div class="col">
              <br><br>
              The Kitchen-Terraform driver is enabled.
              <br><br><br>
              The Kitchen-Terraform provisioner is enabled.
              <br><br>
              The Kitchen-Terraform verifier is configured with two systems.
              <br><br>
              The Test Kitchen backend is configured to use SSH with password authentication to connect to the Docker container.
              <br><br>
              The container system includes a control for the operating system of the Docker container.
              <br><br>
              For each Docker host (see step 3. Create Terraform outputs), the verifier will run the control over SSH on port 2222.
              <br><br>
              The platforms provide arbitrary grouping for the test suite matrix.
              <br><br>
              The suite name corresponds to the directory containing the Inspec profile: <% code("bash") do %>test/integration/example/<% end %>
              <br><br>
            </div>
          </div>
        </div>
        <div class="tab-pane fade" id="list-two" role="tabpanel" aria-labelledby="list-two-list">
          Below is the example Terraform code that uses the Docker provider. The resources created by this code is what
          we'll be testing later on.
          <br><br>
          Create the file <p class="font-weight-bold" style="color: #32c850; display: inline;">versions.tf</p> in the root of the project.
          <br><br>
          <% code("bash") do %>
touch versions.tf
          <% end %>
          Add the following block of code into the file.
          <br><br>
          The configuration is restricted to Terraform versions equal to or greater than 0.14.0 and less than 2.0.0. The
          Docker provider is used to interact with Docker containers and images, it uses the Docker API to manage the
          lifecycle of Docker containers.
          <br><br>
          <% code("ruby") do %>
# Set the required provider and versions
terraform {
  required_version = ">= 0.14.0, < 2.0.0"

  required_providers {
  # We recommend pinning to the specific version of the Docker Provider you're using
  # since new versions are released frequently
    docker = {
      source = "kreuzwerker/docker"
      version = "2.23.1"
      }
    }
  }
          <% end %>
          Create the file <p class="font-weight-bold" style="color: #32c850; display: inline;">main.tf</p> in the root of the project.
          <br><br>
          <% code("bash") do %>
touch main.tf
          <% end %>
          Add each of the following blocks of code into the file.
          <br><br>
          The Docker provider is configured to communicate with a Docker host listening on a Unix socket.
          <br><br>
          <% code("ruby") do %>
provider "docker" {
  host = "unix:///var/run/docker.sock"
}
          <% end %>
          A SSH daemon Docker image from the public registry is configured as a data source.
          <br><br>
          <% code("ruby") do %>
data "docker_registry_image" "ubuntu_sshd" {
  name = "rastasheep/ubuntu-sshd:latest"
}
          <% end %>
          A Docker image is configured on the Docker host using the data source.
          <br><br>
          <% code("ruby") do %>
resource "docker_image" "ubuntu_sshd" {
  keep_locally = true
  name = data.docker_registry_image.ubuntu_sshd.name
  pull_triggers = [data.docker_registry_image.ubuntu_sshd.sha256_digest]
}
          <% end %>
          A Docker container based on the Docker image is configured to be running on the Docker host. The container
          forwards localhost:2222 to its internal SSH daemon.
          <br><br>
          <% code("ruby") do %>
resource "docker_container" "ubuntu" {
  image = docker_image.ubuntu_sshd.latest
  must_run = true
  name = "ubuntu_container"

  ports {
    external = 2222
    internal = 22
  }
}

          <% end %>
        </div>
        <div class="tab-pane fade" id="list-three" role="tabpanel" aria-labelledby="list-three-list">
          To assist with testing, Terraform outputs will provide the path of the backend state file and the container
          host name. The Kitchen-Terraform verifier can use these artifacts to validate the Terraform code.
          <br><br>
          Create the file <p class="font-weight-bold" style="color: #32c850; display: inline;">output.tf</p>
          <br><br>
          <% code("bash") do %>
touch output.tf
          <% end %>
          Add each block of code into the file.
          <br><br>
          <% code("ruby") do %>
output "terraform state" {
  description = "The path to the backend state file"
  value = "${path.module}/terraform.tfstate.d/${terraform.workspace}/terraform.tfstate"
}

output "container_host" {
  description = "The container's host name"
  value = "localhost"
}
          <% end %>
          Refer back to the <p class="font-weight-bold" style="color: #32c850; display: inline;">.kitchen.yml</p> file and in the verifier section
          you will see a reference to the above container host output.
          <br><br>
        </div>
        <div class="tab-pane fade" id="list-four" role="tabpanel" aria-labelledby="list-four-list">
          We've created the Terraform code, now it's time to create the Inspec control tests. Please see the <a href="https://www.inspec.io/docs/reference/profiles/" style="color: #32c850;">Inspec documentation</a> to learn more about profiles and controls.
          <br><br>
          Create a default profile file <p class="font-weight-bold" style="color: #32c850; display: inline;">test/integration/example/inspec.yml</p>
          <br><br>
          <% code("bash") do %>
touch test/integration/examples/inspec.yml
          <% end %>
          Add the block below into the file.
          <br><br>
          <% code("yml") do %>
---
name: default
          <% end %>
          Referring back to the <p class="font-weight-bold" style="color: #32c850; display: inline;">.kitchen.yml</p> file and inside the verifier section there is an operating_system control which we need to create.
          <br><br>
          Create the file <p class="font-weight-bold" style="color: #32c850; display: inline;">test/integration/example/controls/operating_system.rb</p>
          <% code("ruby") do %>
# frozen_string_literal: true

control 'operating_system' do
  describe command("lsb_release -a") do
    its('stderr') { should match /lsb_release: command not found/ }
  end

  describe command('uname -ar') do
    its('stdout') { should match(/Linux/) }
  end

  describe command("env -i bash -c '. /etc/os-release; echo $NAME'") do
    its('stdout') { should match /Ubuntu/ }
  end
end
          <% end %>
          Let's create the state_files control, which will validate the Terraform state file is created and has the proper content.
          <br><br>
          Create the file <p class="font-weight-bold" style="color: #32c850; display: inline;">test/integration/example/controls/state_file.rb</p>
          <% code("ruby") do %>
# frozen_string_literal: true

terraform_state = input('terraform_state', {})

control 'state_files' do
  describe 'the terraform state file' do
    subject do
      file terraform_state
    end

    it do
      is_expected.to exist
    end
  end
end
          <% end %>
          <br><br>
        </div>
        <div class="tab-pane fade" id="list-five" role="tabpanel" aria-labelledby="list-five-list">
          <strong>Before commencing this section of the tutorial please ensure docker is running on your machine, failure to do
          will mean that you will not be able to successfully run the commands.</strong>
          <br><br>
          Execute Kitchen-Terraform by running the command below in the terminal:
          <br><br>
          <% code("ruby") do %>
bundle exec kitchen converge
          <% end %>
          This creates resources from the Terraform code in the main.tf file. Below is an example output of
          Kitchen-Terraform running when you use the <strong>converge</strong> command.
          <br><br>
          <% code("bash") do %>
-----> Starting Test Kitchen (v3.4.0)
-----> Creating <example-ubuntu>...
$$$$$$ Reading the Terraform client version...
       Terraform v0.14.0
       + provider registry.terraform.io/kreuzwerker/docker v2.23.1

       Your version of Terraform is out of date! The latest version
       is 1.3.6. You can update by downloading from https://www.terraform.io/downloads.html
$$$$$$ Finished reading the Terraform client version.
$$$$$$ Verifying the Terraform client version is in the supported interval of >= 0.11.4, < 2.0.0...
$$$$$$ Finished verifying the Terraform client version.
$$$$$$ Initializing the Terraform working directory...

       Initializing the backend...

       Initializing provider plugins...
       - Finding kreuzwerker/docker versions matching "2.23.1"...
       - Installing kreuzwerker/docker v2.23.1...
       - Installed kreuzwerker/docker v2.23.1 (self-signed, key ID BD080C4571C6104C)

       Partner and community providers are signed by their developers.
       If you'd like to know more about provider signing, you can read about it here:
       https://www.terraform.io/docs/plugins/signing.html

       Terraform has been successfully initialized!
$$$$$$ Finished initializing the Terraform working directory.
$$$$$$ Creating the kitchen-terraform-example-ubuntu Terraform workspace...
       Created and switched to workspace "kitchen-terraform-example-ubuntu"!

       You're now on a new, empty workspace. Workspaces isolate their state,
       so if you run "terraform plan" Terraform will not see any existing state
       for this configuration.
$$$$$$ Finished creating the kitchen-terraform-example-ubuntu Terraform workspace.
       Finished creating <example-ubuntu> (0m3.36s).
-----> Converging <example-ubuntu>...
$$$$$$ Reading the Terraform client version...
       Terraform v0.14.0
       + provider registry.terraform.io/kreuzwerker/docker v2.23.1

       Your version of Terraform is out of date! The latest version
       is 1.3.6. You can update by downloading from https://www.terraform.io/downloads.html
$$$$$$ Finished reading the Terraform client version.
$$$$$$ Verifying the Terraform client version is in the supported interval of >= 0.11.4, < 2.0.0...
$$$$$$ Finished verifying the Terraform client version.
$$$$$$ Selecting the kitchen-terraform-example-ubuntu Terraform workspace...
$$$$$$ Finished selecting the kitchen-terraform-example-ubuntu Terraform workspace.
$$$$$$ Downloading the modules needed for the Terraform configuration...
$$$$$$ Finished downloading the modules needed for the Terraform configuration.
$$$$$$ Validating the Terraform configuration files...
       Success! The configuration is valid.

$$$$$$ Finished validating the Terraform configuration files.
$$$$$$ Building the infrastructure based on the Terraform configuration...
       docker_image.ubuntu_sshd: Creating...
       docker_image.ubuntu_sshd: Creation complete after 0s [id=sha256:49533628fb371c9f1952c06cedf912c78a81fbe3914901334673c369376e077erastasheep/ubuntu-sshd:latest]
       docker_container.ubuntu: Creating...
       docker_container.ubuntu: Creation complete after 1s [id=b2766cde74c528e46638f5ab273476431402f7053668499145bc03a12e07291f]

       Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

       Outputs:

       container_host = "localhost"
       terraform_state = "./terraform.tfstate.d/kitchen-terraform-example-ubuntu/terraform.tfstate"
$$$$$$ Finished building the infrastructure based on the Terraform configuration.
$$$$$$ Reading the output variables from the Terraform state...
$$$$$$ Finished reading the output variables from the Terraform state.
$$$$$$ Parsing the Terraform output variables as JSON...
$$$$$$ Finished parsing the Terraform output variables as JSON.
$$$$$$ Writing the output variables to the Kitchen instance state...
$$$$$$ Finished writing the output variables to the Kitchen instance state.
$$$$$$ Writing the input variables to the Kitchen instance state...
$$$$$$ Finished writing the input variables to the Kitchen instance state.
       Finished converging <example-ubuntu> (0m3.32s).
-----> Test Kitchen is finished. (0m7.86s)

        <% end %>

Now run the Kitchen-Terraform tests using:
          <br><br>
        <% code("ruby") do %>
bundle exec kitchen verify
        <% end %>
          This executes the Inspec controls from the .kitchen.yml verifier section and will run the tests in the
          <strong>operating_system.rb</strong> and <strong>state_file.rb</strong> files.
          The output below is an example of Kitchen-Terraform running when you use the <strong>verify</strong> command.
        <br><br>
        <% code("bash") do %>
-----> Starting Test Kitchen (v3.4.0)
-----> Setting up <example-ubuntu>...
       Finished setting up <example-ubuntu> (0m0.00s).
-----> Verifying <example-ubuntu>...
$$$$$$ Reading the Terraform input variables from the Kitchen instance state...
$$$$$$ Finished reading the Terraform input variables from the Kitchen instance state.
$$$$$$ Reading the Terraform output variables from the Kitchen instance state...
$$$$$$ Finished reading the Terraform output variables from the Kitchen instance state.
$$$$$$ Verifying the systems...
$$$$$$ Verifying the 'docker container' system...

       Profile: default
       Version: (not specified)
       Target:  ssh://root@localhost:2222

       ✔  operating_system: Command: `lsb_release -a`
           ✔  Command: `lsb_release -a` stderr is expected to match /lsb_release: command not found/
           ✔  Command: `uname -ar` stdout is expected to match /Linux/
           ✔  Command: `env -i bash -c '. /etc/os-release; echo $NAME'` stdout is expected to match /Ubuntu/


       Profile Summary: 1 successful control, 0 control failures, 0 controls skipped
       Test Summary: 3 successful, 0 failures, 0 skipped
$$$$$$ Finished verifying the 'docker container' system.
$$$$$$ Verifying the 'terraform state' system...

       Profile: default
       Version: (not specified)
       Target:  local://

       ✔  state_files: the terraform state file
           ✔  the terraform state file is expected to exist


       Profile Summary: 1 successful control, 0 control failures, 0 controls skipped
       Test Summary: 1 successful, 0 failures, 0 skipped
$$$$$$ Finished verifying the 'terraform state' system.
$$$$$$ Finished verifying the systems.
       Finished verifying <example-ubuntu> (0m6.20s).
-----> Test Kitchen is finished. (0m7.62s)
        <% end %>
          Once you are finished running the tests with:
          <br><br>
          <% code("ruby") do %>
bundle exec kitchen verify
          <% end %>
          Run the following in the terminal:
          <br><br>
          <% code("bash") do %>
bundle exec kitchen destroy
          <% end %>
          This will destroy the docker container and delete all information for that instance.
          <br><br>
      </div>
    </div>
  </div>
</div>
</div>
